package com.swallow.auth.web.global;

import com.swallow.auth.common.enums.ErrorCode;
import com.swallow.auth.common.exception.BizException;
import com.swallow.auth.common.exception.ParamException;
import com.swallow.auth.common.exception.SysException;
import com.swallow.auth.common.result.R;
import com.swallow.auth.common.result.Result;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.ObjectError;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * @author: 18310740596@163.com
 * @since: 2023-11-21 13-44-53
 * @version: V1.0
 * @describe: 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = BizException.class)
    public Result<Void> bizExceptionHandler(BizException e) {
        String tag = generateTraceId();
        log.error("GLOBAL-EXP -> 业务异常{}", tag, e);
        return R.error(e.getErrorCode(), concatTag(e, "业务异常", tag));
    }

    @ExceptionHandler(value = ParamException.class)
    public Result<Void> paramExceptionHandler(ParamException e) {
        String tag = generateTraceId();
        log.error("GLOBAL-EXP -> 参数异常{}", tag, e);
        return R.error(e.getErrorCode(), concatTag(e, "参数异常", tag));
    }

    private<E extends Throwable> String concatTag(E e, String errorType, String tag) {
        String message = e.getMessage();
        return StringUtils.isBlank(message) ? errorType.concat(tag) : message.concat(tag);
    }

    @ExceptionHandler(value = SysException.class)
    public Result<Void> sysExceptionHandler(SysException e) {
        String tag = generateTraceId();
        log.error("GLOBAL-EXP -> 系统异常{}", tag, e);
        return R.error(e.getErrorCode(), concatTag(e, "系统异常", tag));
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result<Void> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        String tag = generateTraceId();
        log.info("GLOBAL-EXP -> 参数校验错误{}", tag, e);
        String errorMsg = e.getBindingResult().getAllErrors().stream()
                                                            .map(ObjectError::getDefaultMessage)
                                                            .collect(Collectors.joining(","));

        return R.error(ErrorCode.SYSTEM_ERROR.getValue(),
                            StringUtils.isBlank(errorMsg) ? "参数校验错误".concat(tag) : errorMsg.concat(tag));
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public Result<Void> constraintViolationException(ConstraintViolationException e) {
        String tag = generateTraceId();
        log.info("GLOBAL-EXP ->  参数校验错误{}", tag, e);

        String errorMsg = e.getConstraintViolations().stream()
                                                     .map(ConstraintViolation::getMessage)
                                                     .collect(Collectors.joining(System.lineSeparator()));

        return R.error(ErrorCode.SYSTEM_ERROR.getValue(),
                            StringUtils.isBlank(errorMsg) ? "参数校验错误".concat(tag) : errorMsg.concat(tag));
    }

    @ExceptionHandler(value = HandlerMethodValidationException.class)
    public Result<Void> handlerMethodValidationException(HandlerMethodValidationException e) {
        String tag = generateTraceId();
        log.info("GLOBAL-EXP ->  参数校验错误{}", tag, e);

        String message = e.getAllValidationResults()
                          .stream()
                          .map(ParameterValidationResult::getResolvableErrors)
                          .map(item -> item.getFirst().getDefaultMessage())
                          .collect(Collectors.joining(","));

        return R.error(message.concat(tag));
    }

    /**
     * 处理其他异常
     * @param e 异常
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    public Result<Void> exceptionHandler(Exception e){
        String tag = generateTraceId();
        log.error("GLOBAL-EXP -> 未知异常{}", tag, e);
        return R.error(ErrorCode.SYSTEM_ERROR.getValue(), "未知异常".concat(tag));
    }
    /**
     *  括号前缀
     */
    private static final String PARENTHESIS_PREFIX = "(";

    /**
     *  括号后缀
     */
    private static final String PARENTHESIS_SUFFIX = ")";
    /**
     *  生成字母,数字随机数
     *
     * @return 随机数
     */
    private static String generateTraceId() {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        StringBuilder random = new StringBuilder();
        random.append(PARENTHESIS_PREFIX);
        int count = ThreadLocalRandom.current().nextInt(10000, 99999);
        while (count > 0) {
            int val = count % 10;
            random.append(uuid.charAt(val));
            count /= 10;
        }
        random.append(PARENTHESIS_SUFFIX);
        return random.toString();
    }
}
